package com.vf.cloud.pass.mvc.biz.controller;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.bson.types.Binary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Page;
import com.vf.cloud.pass.common.datasource.annotation.Tx;
import com.vf.cloud.pass.common.domain.biz.Config;
import com.vf.cloud.pass.common.domain.biz.Project;
import com.vf.cloud.pass.common.domain.biz.ProjectShare;
import com.vf.cloud.pass.common.domain.biz.Scene;
import com.vf.cloud.pass.common.domain.sys.Dict;
import com.vf.cloud.pass.common.domain.sys.DictItem;
import com.vf.cloud.pass.common.domain.sys.User;
import com.vf.cloud.pass.common.repository.base.Thumbnail;
import com.vf.cloud.pass.common.util.DateUtil;
import com.vf.cloud.pass.common.util.R;
import com.vf.cloud.pass.common.util.UuidUtil;
import com.vf.cloud.pass.common.util.WebUtils;
import com.vf.cloud.pass.common.vo.ProjectDebug;
import com.vf.cloud.pass.common.vo.ProjectPreview;
import com.vf.cloud.pass.mvc.biz.service.IThumbnail;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@RestController
@RequestMapping("/biz/project")
public class ProjectController {

	@Autowired
	private IThumbnail thumbnailImpl;

	@GetMapping(value = { "/list" }, produces = "application/json; charset=utf-8")
	public R<Page<Project>> findList(HttpServletRequest request,
			@RequestParam(name = "keywords", required = false, defaultValue = "") String keywords,
			@RequestParam(name = "status", required = false, defaultValue = "") String status,
			@RequestParam(name = "cur", required = false, defaultValue = "1") int cur,
			@RequestParam(name = "limit", required = false, defaultValue = "10") int limit) throws Exception {

		User user=WebUtils.getCurUser(request);
		
		
		String sqlExceptSelect = " from biz_project a LEFT JOIN biz_scene b ON a.scene_id=b.id WHERE a.type='0' and a.status='1' and a.org_id='"+user.getOrgId()+"' ";
		if (!StrKit.isBlank(keywords)) {
			sqlExceptSelect += " AND ( b.NAME LIKE '%" + keywords + "%' ) ";
		}
		sqlExceptSelect += "  ORDER BY   b.UPDATE_TIME desc ";
		Page<Project> pages = Project.dao.paginate(cur, limit,
				"select a.id ,a.org_id, a.scene_id ,a.limit,a.name ,(select org_name from sys_user where id=a.org_id ) as org_name,b.update_time ",
				sqlExceptSelect);
		return R.ok(pages);
	}
	

	@Tx
	@RequestMapping(value = "/save", method = RequestMethod.POST)
	public R<Project> save(HttpServletRequest request, Project model) {
		try {

			if (StrKit.notBlank(model.getId())) {
				model.setUpdateTime(DateUtil.getLocalDateTime());
				User user = WebUtils.getCurUser(request);
				if (user != null) {
					model.setUpdateBy(user.getId());
				}
				model.setUpdateTime(DateUtil.getLocalDateTime());
				if (model.update()) {
					return R.ok(model);
				} else {
					return R.failed("更新失败！");
				}
			} else {
				model.setId(UuidUtil.getUUID());

				User user = WebUtils.getCurUser(request);
				if (user != null) {
					model.setOrgId(user.getOrgId());
					model.setCreateBy(user.getId());
				}
				model.setCreateTime(DateUtil.getLocalDateTime());
				if (model.save()) {
					return R.ok(model);
				} else {
					return R.failed("保存失败！");
				}
			}
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
	}

	@Tx
	@RequestMapping(value = "/deleteById", method = RequestMethod.GET)
	public R<String> deleteById(@RequestParam(name = "id") String id) throws Exception {
		try {
			Project model = Project.dao.findById(id);
			if (model == null)
				return R.failed("数据不存在，刷新后尝试!");
			if (model.delete()) {
				return R.ok();
			}

			return R.failed("失败！");
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
	}

	@RequestMapping(value = "/getById", method = RequestMethod.GET)
	public R<Project> getById(@RequestParam(name = "id") String id) throws Exception {
		try {
			Project sever = Project.dao.findById(id);
			if (sever == null)
				return R.failed("数据不存在，刷新后尝试!");
			return R.ok(sever);
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
	}

	@RequestMapping(value = "/getTypes", method = RequestMethod.GET)
	public R<Dict> getTypes() throws Exception {
		try {

			Dict dict = Dict.dao.findByCode("Industry");
			if (dict != null) {
				List<DictItem> items = DictItem.dao.find(
						"select * from " + DictItem.TABLE_NAME + " where DICT_ID=? order by sort asc ", dict.getId());
				dict.setItems(items);
				return R.ok(dict);
			} else {
				return R.failed();
			}
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
	}

	@RequestMapping(value = "/share", method = RequestMethod.GET)
	public R<ProjectShare> share(@RequestParam(name = "projectId") String projectId) throws Exception {

		try {

			Project project = Project.dao.findById(projectId);
			if (project == null) {
				return R.failed("分享应用未找到.");
			}
			Scene scene = Scene.dao.findById(project.getSceneId());

			if (scene == null) {
				return R.failed("分享应用场景不存在.");
			}

			Config config = Config.dao.findById("vf_cloud_pass_2022");

			if (config == null) {
				return R.failed("请先配置分享域名.");
			}

			ProjectShare sceneShare = new ProjectShare();
			sceneShare.setId(UuidUtil.getUUID());
			sceneShare.setProjectId(project.getSceneId());
			sceneShare.setName(project.getName());
			sceneShare.setCreateTime(DateUtil.getLocalDateTime());
			sceneShare.setLimitedTime(1);
			sceneShare.setResX(scene.getResX());
			sceneShare.setResY(scene.getResY());

			if (StrKit.equals("80", config.getPort())) {
				sceneShare.setUrl(String.format("http://%s?appId=%s", config.getIp(), project.getId()));
			} else {
				sceneShare.setUrl(
						String.format("http://%s:%s?appId=%s", config.getIp(), config.getPort(), project.getId()));
			}

			sceneShare.setScene(scene);

			String format = "png";
			Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			hints.put(EncodeHintType.MARGIN, 1);

			BitMatrix bitMatrix = new MultiFormatWriter().encode(String.format("%s", sceneShare.getId()),
					BarcodeFormat.QR_CODE, 400, 400, hints);
			BufferedImage image = toBufferedImage(bitMatrix);
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			ImageIO.write(image, format, os);

			Thumbnail thumbnailEntity = new Thumbnail();
			thumbnailEntity.setId(sceneShare.getId());
			thumbnailEntity.setSize(1);
			thumbnailEntity.setUploadDate(new Date(System.currentTimeMillis()));
			thumbnailEntity.setContent(new Binary(os.toByteArray()));
			if (sceneShare.save()) {
				thumbnailImpl.save(thumbnailEntity);
				os.close();
				return R.ok(sceneShare);
			} else {
				return R.failed();
			}
		} catch (IOException e) {
			return R.failed(e.getMessage());
		}

	}

	@RequestMapping(value = "/updateShare", method = RequestMethod.POST)
	public R<ProjectShare> updateShare(ProjectShare model) {
		try {
			ProjectShare sceneShare = ProjectShare.dao.findById(model.getId());
			if (sceneShare == null) {
				return R.failed();
			}
			if (model.update()) {
				return R.ok(sceneShare);
			} else {
				return R.failed();
			}
		} catch (Exception e) {
			return R.failed(e.getMessage());
		}
	}

	private final int BLACK = 0xFF000000;
	private final int WHITE = 0xFFFFFFFF;

	private BufferedImage toBufferedImage(BitMatrix matrix) {
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
			}
		}
		return image;
	}

	@RequestMapping(value = "/preview", method = RequestMethod.GET)
	public R<ProjectPreview> preview(@RequestParam(name = "projectId") String projectId) throws Exception {

		Project project = Project.dao.findById(projectId);
		if (project == null) {
			return R.failed("预览应用未找到.");
		}
		Scene scene = Scene.dao.findById(project.getSceneId());

		if (scene == null) {
			return R.failed("预览应用场景不存在.");
		}

		Config config = Config.dao.findById("vf_cloud_pass_2022");

		if (config == null) {
			return R.failed("请先配置预览地址.");
		}

		ProjectPreview projectPreview = new ProjectPreview();
		projectPreview.setProject(project);
		projectPreview.setScene(scene);

		projectPreview.setUrl(config.getPreviewUrl());

		return R.ok(projectPreview);

	}
	
	@RequestMapping(value = "/debug", method = RequestMethod.GET)
	public R<ProjectDebug> debug(@RequestParam(name = "projectId") String projectId) throws Exception {

		Project project = Project.dao.findById(projectId);
		if (project == null) {
			return R.failed("预览应用未找到.");
		}
		Scene scene = Scene.dao.findById(project.getSceneId());

		if (scene == null) {
			return R.failed("预览应用场景不存在.");
		}

		Config config = Config.dao.findById("vf_cloud_pass_2022");

		if (config == null) {
			return R.failed("请先配置调式地址.");
		}

		ProjectDebug projectDebug = new ProjectDebug();
		projectDebug.setProject(project);
		projectDebug.setScene(scene);
		projectDebug.setUrl(config.getDebugUrl());

		return R.ok(projectDebug);

	}

}
